﻿/*
 *
 * serial.c
 *
 *  Created on: 2017年3月28日
 *      Author: chenshisheng
 */

#include "serial.h"
#include "usart.h"
#include "active.h"

#include <assert.h>
#include <stdarg.h>
#include <string.h>

#define ENABLE_AUTO_NEW_LINE 1

#if SERIAL_NUM == 0
#   error "No UART device enabled!"
#endif

#define Serial_Max (SERIAL_NUM - 1)

// 串口收发控制结构
typedef struct
{
    bool txStarted;                        // 指示是否已经启动发送
    USART_TypeDef* uart;                   // 标准库函数操作串口所用的句柄
    rbuf_t rxRingBuffer;                   // 接收队列
    uint8_t _rxBuf[SERIAL_RX_BUFFER_SIZE]; // 接收缓存
    rbuf_t txRingBuffer;                   // 发送队列
    uint8_t _txBuf[SERIAL_TX_BUFFER_SIZE]; // 发送缓存
    Serial_Callback_t onTxBegin;           // 开始发送数据时的调用的回调函数
    Serial_Callback_t onTxComplete;        // 发送完成时调用的回调函数
    Serial_RxByteCallback_t onRxByte;      // 接收到一个字节时调用的回调函数
    uint32_t flags;
}Serial_Ctrl_t;

typedef struct
{
    USART_TypeDef *uart;
    const char *name;
    void (*init)(void);
}Serial_Config_t;

struct income
{
    Serial_t serial;
    uint8_t  byte;
};

// 串口序号对应的标准库函数操作串口所用的句柄
static const Serial_Config_t _configs[SERIAL_NUM] =
{
#if SERIAL_USE_USART1
        {USART1, "Serial_1", MX_USART1_UART_Init},
#endif

#if SERIAL_USE_USART2
        {USART2, "Serial_2", MX_USART2_UART_Init},
#endif

#if SERIAL_USE_USART3
        {USART3, "Serial_3", MX_USART3_UART_Init},
#endif

#if SERIAL_USE_UART4
        {USART4,  "Serial_4", MX_USART4_UART_Init},
#endif

#if SERIAL_USE_UART5
        {USART5,  "Serial_5", MX_USART5_UART_Init},
#endif

#if SERIAL_USE_UART6
        {USART6, "Serial_6", MX_USART6_UART_Init},
#endif

#if SERIAL_USE_LPUART1
        {LPUART1, "Serial_LP1", MX_LPUART1_UART_Init},
#endif
};

static Serial_Ctrl_t _ctrls[SERIAL_NUM];
static unsigned int _actionBits;

static void _DefaultCB(Serial_t serial);
static bool _DefaultRxByteCB(Serial_t serial, uint8_t b);
static bool _OnRxOnTest(Serial_t serial, uint8_t b);

void Serial_Init(void)
{
    unsigned int i;
    Serial_Ctrl_t *ctrl;

    _actionBits = 0;

    // 初始化串口收发控制结构
    for(i = 0; i < ARRAY_SIZE(_configs); i++)
    {
        ctrl = & _ctrls[i];

        ctrl->txStarted = FALSE;
        ctrl->flags = 0;
        ctrl->uart = _configs[i].uart;
        RingBuffer_Init(& ctrl->rxRingBuffer, ctrl->_rxBuf, sizeof(ctrl->_rxBuf));
        RingBuffer_Init(& ctrl->txRingBuffer, ctrl->_txBuf, sizeof(ctrl->_txBuf));
        ctrl->onTxBegin = _DefaultCB;
        ctrl->onTxComplete = _DefaultCB;
        ctrl->onRxByte = _DefaultRxByteCB;

        _configs[i].init();
        LL_USART_EnableIT_RXNE(ctrl->uart);
    }

    // 标准输入输出串口上，缓存满了以后，新的数据覆盖旧的数据 （RINGBUFFER_FLAG_OVERWRITE）
//    RingBuffer_SetFlags(& _ctrls[STDIO_SERIAL].rxRingBuffer, RINGBUFFER_FLAG_OVERWRITE);
//    RingBuffer_SetFlags(& _ctrls[STDIO_SERIAL].txRingBuffer, RINGBUFFER_FLAG_OVERWRITE);

    LL_LPUART_EnableClockInStopMode(LPUART1);
    LL_LPUART_EnableInStopMode(LPUART1);
    LL_LPUART_Enable(LPUART1);
}

static void _DefaultCB(Serial_t serial)
{
    UNUSED(serial);
}

static bool _DefaultRxByteCB(Serial_t serial, uint8_t b)
{
    UNUSED(serial);
    UNUSED(b);
    return false;
}

void Serial_SetCallbacks(
        Serial_t serial,
        Serial_Callback_t onTxBegin,
        Serial_Callback_t onTxComplete,
        Serial_RxByteCallback_t onRxByte)
{
    Serial_Ctrl_t *ctrl;

    assert(serial <= Serial_Max);
    ctrl = & _ctrls[serial];

    if(onTxBegin != NULL)
    {
        ctrl->onTxBegin = onTxBegin;
    }

    if(onTxComplete != NULL)
    {
        ctrl->onTxComplete = onTxComplete;
    }

    if(onRxByte != NULL)
    {
        ctrl->onRxByte = onRxByte;
    }
}

void Serial_GetCallbacks(
        Serial_t serial,
        Serial_Callback_t *onTxBegin,
        Serial_Callback_t *onTxComplete,
        Serial_RxByteCallback_t *onRxByte)
{
    Serial_Ctrl_t *ctrl;

    assert(serial <= Serial_Max);
    ctrl = & _ctrls[serial];

    if(onTxBegin != NULL)
    {
        *onTxBegin = ctrl->onTxBegin;
    }

    if(onTxComplete != NULL)
    {
        *onTxComplete = ctrl->onTxComplete;
    }

    if(onRxByte != NULL)
    {
        *onRxByte = ctrl->onRxByte;
    }
}

void Serial_SendByte(Serial_t serial, uint8_t b)
{
    Serial_Ctrl_t *ctrl;

//    assert(serial <= Serial_Max);
#if ENABLE_AUTO_NEW_LINE
    if((b == '\n') && (_ctrls[serial].flags & SERIAL_FLAG_AUTO_LINE))
    {
        Serial_SendByte(serial, '\r');
    }
#endif

    ctrl = & _ctrls[serial];
    if(! ctrl->txStarted)
    {
        BIT_SET(_actionBits, 0x01 << serial);
        Active_Set(Active_Serail, true);
        ctrl->onTxBegin(serial);
        LL_USART_TransmitData8(ctrl->uart, b);
        ctrl->txStarted = true;
        LL_USART_EnableIT_TXE(ctrl->uart);
    }
    else
    {
        while(RingBuffer_Write(& ctrl->txRingBuffer, & b) != 0)
        {
            IDLE();
        }
    }
}

void Serial_Send(Serial_t serial, const void *dataIn, unsigned int size)
{
    const uint8_t *vdata;
    unsigned int i;

    vdata = dataIn;
    for(i = 0; i < size; i++)
    {
        Serial_SendByte(serial, vdata[i]);
    }
}

void Serial_SendString(Serial_t serial, const char *str)
{
    char c;

    while(1)
    {
        c = *str++;
        if(c == '\0')
        {
            break;
        }

        Serial_SendByte(serial, c);
    }
}

void Serial_IRQHandler(Serial_t serial)
{
    Serial_Ctrl_t *ctrl;
    uint8_t b;

    ctrl = & _ctrls[serial];
    if(LL_USART_IsActiveFlag_RXNE(ctrl->uart) &&
            LL_USART_IsEnabledIT_RXNE(ctrl->uart))
    {
        b = LL_USART_ReceiveData8(ctrl->uart);
        if(ctrl->onRxByte(serial, b))
        {
            RingBuffer_Write(& ctrl->rxRingBuffer, & b);
        }
    }

    if(LL_USART_IsActiveFlag_TXE(ctrl->uart) &&
            LL_USART_IsEnabledIT_TXE(ctrl->uart))
    {
        if(RingBuffer_Read(& ctrl->txRingBuffer, & b) == 0)
        {
            ctrl->txStarted = TRUE;
            LL_USART_TransmitData8(ctrl->uart, b);
        }
        else
        {
            LL_USART_DisableIT_TXE(ctrl->uart);
            LL_USART_ClearFlag_TC(ctrl->uart);
            LL_USART_EnableIT_TC(ctrl->uart);
            ctrl->txStarted = FALSE;
        }
    }

    if(LL_USART_IsActiveFlag_TC(ctrl->uart) &&
            LL_USART_IsEnabledIT_TC(ctrl->uart))
    {
        LL_USART_DisableIT_TC(ctrl->uart);
        ctrl->onTxComplete(serial);

        BIT_CLR(_actionBits, 0x01 << serial);
        if(_actionBits == 0)
        {
            Active_Set(Active_Serail, false);
        }
    }
}

int Serial_RecvByte(Serial_t serial, uint8_t *byteOut)
{

//    assert(serial <= Serial_Max);

    return RingBuffer_Read(& _ctrls[serial].rxRingBuffer, byteOut);
}

void Serial_ClearTxBuffer(Serial_t serial)
{
    RingBuffer_Clear(& _ctrls[serial].txRingBuffer);
}

void Serial_ClearRxBuffer(Serial_t serial)
{
    RingBuffer_Clear(& _ctrls[serial].rxRingBuffer);
}

#if 0
/**
 *
 * @param pt
 * @param serial
 * @param dataOut
 * @param size
 * @param timeoutMs
 * @param statusOut
 * @return
 */
PT_THREAD(Serial_RecvThread(
        struct pt *pt,
        Serial_t serial,
        void *dataOut,
        unsigned int size,
        unsigned int timeoutMs,
        int *statusOut))
{
    static unsigned int i;
    static uint8_t *vdata;
    static Timer_t timeout;

    PT_BEGIN(pt);

    Timer_Set(& timeout, timeoutMs);

    vdata = dataOut;
    for(i = 0; i < size; i++)
    {
        PT_WAIT_UNTIL(pt,
                (Serial_RecvByte(serial, vdata) == 0) || Timer_Expired(& timeout));
        if(Timer_Expired(& timeout))
        {
            *statusOut = -1;
            PT_EXIT(pt);
        }

        vdata += 1;
    }

    *statusOut = 0;
    PT_EXIT(pt);

    PT_END(pt);
}
#endif

/**
 * @brief 从串口接收带回车结尾的一行字符
 * @param serial 串口序号
 * @param buf    字符缓存
 * @param size   字符缓存大小
 * @param end    行结尾符
 * @return 0  接收成功
 *         -1 接收失败
 */
int Serial_RecvLine(Serial_t serial, char buf[], unsigned int size, char end)
{
    size_t i;
    int ret;
    char c;
    rbuf_t *rxRbuf;

    rxRbuf = & _ctrls[serial].rxRingBuffer;
    ret = -1;
    for(i = 0; i < (size - 1); i++)
    {
        if(RingBuffer_Read(rxRbuf, & c) == -1)
        {
            break;
        }

        if(c == end)
        {
            ret = 0;
            break;
        }

        buf[i] = c;
    }

    buf[i] = '\0';
    return ret;
}

void Serial_Cmd(Serial_t serial, FunctionalState NewState)
{
    if(NewState == DISABLE)
    {
        LL_USART_Disable(_ctrls[serial].uart);
    }
    else
    {
        LL_USART_Enable(_ctrls[serial].uart);
    }
}

static bool _OnRxOnTest(Serial_t serial, uint8_t b)
{
    UNUSED(b);

    MsgQueue_Send(MsgQueue_Id_SerialTest, & serial, sizeof(serial));
    return TRUE;
}

void Serial_TestCmd(Serial_t serial, bool isEnable)
{
    Serial_RxByteCallback_t cb;

    cb = isEnable ? _OnRxOnTest : _DefaultRxByteCB;
    Serial_SetCallbacks(serial, NULL, NULL, cb);
}

void Serial_OnTest(MsgQueue_Msg_t *msg)
{
    Serial_t serial;
    uint8_t b;
//    Timer_t timer;

    memcpy(& serial, msg->data, sizeof(serial));
//    if(_ctrls[serial].onTxBegin != _DefaultCB)   // 大致判断是不是RS485串口
//    {
//        // 若是RS485串口，则等待一段时间再发以避免冲突
//        Timer_Set(& timer, 20);
//        while(! Timer_Expired(& timer));
//    }

    while(Serial_RecvByte(serial, & b) == 0)
    {
        Serial_SendByte(serial, b);
    }
}

void Serial_Config(Serial_t serial, LL_USART_InitTypeDef* USART_InitStruct)
{
    LL_USART_Init(_configs[serial].uart, USART_InitStruct);
}

const char *Serial_GetName(Serial_t serial)
{
    return _configs[serial].name;
}

void Serial_SetFlag(Serial_t serial, uint32_t flags)
{
    BIT_SET(_ctrls[serial].flags, flags);
}

void Serial_ClrFlag(Serial_t serial, uint32_t flags)
{
    BIT_CLR(_ctrls[serial].flags, flags);
}

uint32_t Serial_GetBaudRate(Serial_t serial)
{
    USART_TypeDef* uart = _ctrls[serial].uart;
    LL_RCC_ClocksTypeDef RCC_Clocks;
    uint32_t PeriphClk;

//    if(uart == USART1)
//    {
//        PeriphClk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
//    }
//    else
    {
        LL_RCC_GetSystemClocksFreq(&RCC_Clocks);
        PeriphClk = RCC_Clocks.PCLK1_Frequency;
    }

//    OverSampling = LL_USART_GetOverSampling(uart);
    return LL_USART_GetBaudRate(uart, PeriphClk, LL_USART_OVERSAMPLING_16);
}

int Serial_IoCtl(int serial, int ctl, ...)
{
    Serial_t s;
    int ret = 0;
    va_list args;

    s = (Serial_t)serial;
    va_start(args, ctl);
    switch(ctl)
    {
    case Serial_Ctl_Cmd:
    {
        FunctionalState state;

        state = (FunctionalState)va_arg(args, int);
        Serial_Cmd(s, state);
    }
        break;

    case Serial_Ctl_Reconfig:
        break;

    case Serial_Ctl_SetFlag:
        break;

    case Serial_Ctl_ClearFlag:
        break;

    case Serial_Ctl_ClearBuffer:
        break;

    case Serial_Ctl_GetBuadRate:
        break;

    case Serial_Ctl_RxCmd:
    {
        FunctionalState state;

        state = (FunctionalState)va_arg(args, int);
        if(state == DISABLE)
        {
            LL_USART_DisableIT_RXNE(_ctrls[s].uart);
        }
        else
        {
            LL_USART_ClearFlag_NE(_ctrls[s].uart);
            LL_USART_EnableIT_RXNE(_ctrls[s].uart);
        }
    }
        break;

    default:
        ret = -1;
        break;
    }

    va_end(args);
    return  ret;
}

int __io_putchar(int ch)
{
    Serial_SendByte(STDIO_SERIAL, (uint8_t)ch);
    return ch;
}

int __io_getchar(void)
{
    uint8_t b;
    int ret;

    do
    {
        ret = Serial_RecvByte(STDIO_SERIAL, &b);
    }while(ret != 0);

    return b;
}
